package blackstar.plugin.jmxproxy;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Set;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;

import mx4j.tools.remote.proxy.RemoteMBeanProxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import blackstar.agent.jvm.JMXProxy;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class JMXRemoteProxy
{
	private final static Log LOGGER = LogFactory.getLog(JMXRemoteProxy.class);

	private final JMXProxy jmxProxy;

	private JMXConnectorServer proxyConnectorServer;

	public JMXRemoteProxy(JMXProxy jmxProxy)
	{
		super();
		this.jmxProxy = jmxProxy;
	}

	public synchronized void start()
	{
		try
		{
			startJMXProxy();

		} catch (Exception e)
		{
			LOGGER.error("Start AgentProxy failed", e);

			stop();
		}
	}

	public synchronized void stop()
	{
		if (proxyConnectorServer != null)
		{
			LOGGER.info("stop RemoteProxy[" + proxyConnectorServer.getAddress()
					+ "]");

			try
			{
				proxyConnectorServer.stop();
			} catch (Exception e)
			{
				LOGGER.error("Stop AgentProxy failed", e);
			}
			proxyConnectorServer = null;
		}
	}

	private void startJMXProxy() throws IOException,
			MalformedObjectNameException, InstanceAlreadyExistsException,
			MBeanRegistrationException, NotCompliantMBeanException,
			MalformedURLException
	{
		String serverId = "LocalJVM_" + jmxProxy.getId();

		MBeanServer server = proxyRemoteBean(jmxProxy
				.getLocalMBeanServerConnection(), serverId);

		proxyConnectorServer = JMXRemoteProxyUtil.createJMXConnectorServer("/"
				+ jmxProxy.getId(), server);
		proxyConnectorServer.start();

		this.jmxProxy.getProperties().put("JMXServiceURL",
				proxyConnectorServer.getAddress().toString());

		LOGGER.info("start RemoteProxy[" + proxyConnectorServer.getAddress()
				+ "]");
	}

	public static MBeanServer proxyRemoteBean(
			MBeanServerConnection remoteMBeanServerConnection, String serverId)
			throws MalformedObjectNameException, NullPointerException,
			IOException, InstanceAlreadyExistsException,
			MBeanRegistrationException, NotCompliantMBeanException
	{
		Set<ObjectName> set = remoteMBeanServerConnection.queryNames(
				new ObjectName("*:*"), null);

		MBeanServer server = MBeanServerFactory.createMBeanServer(serverId);

		for (ObjectName on : set)
		{
			if (!"JMImplementation".equals(on.getDomain()))
			{
				server.registerMBean(new RemoteMBeanProxy(on,
						remoteMBeanServerConnection), on);
			}
		}
		return server;
	}
}
